home *** CD-ROM | disk | FTP | other *** search
/ Visual Basic Source Code / Visual Basic Source Code.iso / vbsource / ftpser1a / ftp_srv2.bas < prev    next >
Encoding:
BASIC Source File  |  1999-10-04  |  19.6 KB  |  560 lines

  1. Attribute VB_Name = "FTP_Srv2"
  2. Option Explicit
  3.  
  4. Sub ServerLog(ByVal Str As String)
  5.   FtpServ.LogWnd.AddItem Str
  6.   FtpServ.LogWnd.Selected(FtpServ.LogWnd.ListCount - 1) = True
  7. End Sub
  8.  
  9. 'EXEC A FTP COMMAND:
  10. '<id_user> is a number in the range 1 to MAX_N_USERS
  11. 'identifing the user who sends the command;
  12. '<cmd> is the command.
  13.  
  14. Function exec_FTP_cmd(Id_User As Integer, cmd As String) As Integer
  15. Dim Kwrd As String 'keyword
  16. Dim Argument(5) As String 'arguments
  17. Dim ArgN As Long
  18. Dim FTP_Err As Integer 'error
  19. Dim PathName As String, Drv As String
  20.  
  21. Dim Full_Name As String 'pathname & file name
  22. Dim File_Len As Long 'file lenght in bytes
  23. Dim i As Long
  24.  
  25. Dim Ok As Integer
  26. Dim Buffer As String
  27. Dim DummyS As String
  28.  
  29.  
  30. 'variables used during the data exchange
  31. Dim ExecSlot As Integer
  32. Dim NewSockAddr As SockAddr, LclSockAddr As SockAddr
  33.  
  34. On Error Resume Next 'routine for error interception
  35.  
  36. FTP_Err = sintax_ctrl(cmd, Kwrd, Argument())
  37. 'log commands
  38. ServerLog "<" & Format$(Id_User, "000") & "> " & Format$(Date$, "dd/mm/yy ") & Format$(Time$, "hh:mm - ") & cmd
  39. If FTP_Err <> 0 Then
  40.   retf = send_reply(sintax_error_list(FTP_Err), Id_User)
  41.   Exit Function
  42. End If
  43.  
  44. Select Case UCase$(Kwrd)
  45.   Case "USER":  'USER <username>
  46.   Ok = False
  47.   Debug.Print N_RECOGNIZED_USERS;
  48.   For i = 1 To N_RECOGNIZED_USERS
  49.     'Debug.Print UserIDs.No(i).Name
  50.     'controls if the user is in the list of known users
  51.     If Argument(0) = UserIDs.No(i).Name Then
  52.       'the user must enter a password but anonymous users can be accepted
  53.       If UserIDs.No(i).Name = "anonymous" Then
  54.         retf = send_reply("331 User anonymous accepted, please type your e-mail address as password.", Id_User)
  55.       Else
  56.         retf = send_reply("331 User name Ok, type in your password.", Id_User)
  57.       End If
  58.       users(Id_User).list_index = i
  59.       users(Id_User).cur_dir = UserIDs.No(i).Home
  60.       users(Id_User).state = 1
  61.       Ok = True
  62.       Exit For
  63.     End If
  64.   Next
  65.   If Not Ok Then  'unknown user
  66.     retf = send_reply("530 Not logged in, user " & Argument(0) & " is unknown.", Id_User)
  67.     retf = logoff(Id_User)
  68.   End If
  69.  
  70.   Case "PASS": 'PASS <password>
  71.   If users(Id_User).state = 1 Then
  72.     If LCase(UserIDs.No(users(Id_User).list_index).Name) = "anonymous" Then
  73.       'anonymous user
  74.       retf = send_reply("230 User anonymous logged in, proceed.", Id_User)
  75.       users(Id_User).state = 2
  76.     Else
  77.       If Argument(0) = UserIDs.No(users(Id_User).list_index).Pass Then
  78.         'correct password, the user can proceed
  79.         retf = send_reply("230 User logged in, proceed.", Id_User)
  80.         users(Id_User).state = 2
  81.       Else
  82.         'wrong password, the user is disconnected
  83.         retf = send_reply("530 Not logged in, wrong password.", Id_User)
  84.         retf = logoff(Id_User)
  85.       End If
  86.     End If
  87.   Else
  88.     'the user must enter his name
  89.     retf = send_reply("503 I need your username.", Id_User)
  90.   End If
  91.   
  92.   Case "CWD", "XCWD": 'CWD <pathname>
  93.   If users(Id_User).state = 2 Then
  94.     PathName = ChkPath(Id_User, Argument(0))
  95.     Drv = Left(PathName, 2)
  96.     ChDrive Drv
  97.     ChDir PathName
  98.     If Err.Number = 0 Then
  99.       users(Id_User).cur_dir = CurDir
  100.       'existing directory
  101.       retf = send_reply("250 CWD command executed.", Id_User)
  102.     ElseIf (Err.Number > 51 And Err.Number < 77) Or (Err.Number > 707 And Err.Number < 732) Then
  103.       'no existing directory
  104.       retf = send_reply("550 CWD command not executed: " & Error$, Id_User)
  105.     Else
  106.       'FtpServ.StatusBar.panels(1) = "Error " & CStr(Err) & " occurred."
  107.       retf = logoff(Id_User)
  108.       'End
  109.     End If
  110.   Else
  111.     'user not logged in
  112.     retf = send_reply("530 User not logged in.", Id_User)
  113.   End If
  114.  
  115.   Case "CDUP", "XCUP": 'CDUP
  116.   If users(Id_User).state = 2 Then
  117.     ChDir users(Id_User).cur_dir
  118.     ChDir ".."
  119.     users(Id_User).cur_dir = CurDir
  120.     retf = send_reply("200 CDUP command executed.", Id_User)
  121.   Else
  122.     retf = send_reply("530 User not logged in.", Id_User)
  123.   End If
  124.  
  125.   Case "QUIT": 'QUIT
  126.   retf = logoff(Id_User)
  127.  
  128.   Case "PORT": 'PORT <host-port>
  129.   If users(Id_User).state = 2 Then
  130.     'opens a data connection
  131.     ExecSlot = Socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)
  132.     If ExecSlot < 0 Then
  133.       'error
  134.       retf = send_reply("425 Can't build data connection.", Id_User)
  135.     Else
  136.       NewSockAddr.sin_family = PF_INET
  137.       'remote IP address
  138.       IPLong.Byte4 = Val(Argument(0))
  139.       IPLong.Byte3 = Val(Argument(1))
  140.       IPLong.Byte2 = Val(Argument(2))
  141.       IPLong.Byte1 = Val(Argument(3))
  142.       CopyMemory i, IPLong, 4
  143.       NewSockAddr.sin_addr = i
  144.       
  145.       'remote port
  146.       ArgN = Val(Argument(4))
  147.       NewSockAddr.sin_port = htons(ArgN)
  148.       retf = connect(ExecSlot, NewSockAddr, 16)
  149.       If retf < 0 Then
  150.         retf = send_reply("425 Can't build data connection.", Id_User)
  151.       Else
  152.         retf = send_reply("200 PORT command executed.", Id_User)
  153.         'stores the IP-address and port number in user record
  154.         users(Id_User).data_slot = ExecSlot
  155.         users(Id_User).IP_address = Argument(0) & "." & Argument(1) & "." & Argument(2) & "." & Argument(3)
  156.         users(Id_User).Port = Val(Argument(4))
  157.         ServerLog ("IP=" & users(Id_User).IP_address & ":" & Argument(4))
  158.         '<state> field establishes that now is
  159.         'possible to exec commands requiring a data connection
  160.         users(Id_User).state = 3
  161.       End If
  162.     End If
  163.   Else
  164.     retf = send_reply("530 User not logged in.", Id_User)
  165.   End If
  166.  
  167.   Case "TYPE": 'TYPE <type-code>
  168.   If users(Id_User).state = 2 Then
  169.     'stores the access parameters in user record
  170.     retf = send_reply("200 TYPE command executed.", Id_User)
  171.     users(Id_User).data_representation = Argument(0)
  172.     users(Id_User).data_format_ctrls = Argument(1)
  173.   Else
  174.     retf = send_reply("530 User not logged in.", Id_User)
  175.   End If
  176.  
  177.   Case "STRU": 'STRU <structure-code>
  178.   If users(Id_User).state = 2 Then
  179.     'stores access parameters in the user record
  180.     retf = send_reply("200 STRU command executed.", Id_User)
  181.     users(Id_User).data_structure = Argument(0)
  182.   Else
  183.     retf = send_reply("530 User not logged in.", Id_User)
  184.   End If
  185.   
  186.   Case "MODE": 'MODE <mode-code>
  187.   If users(Id_User).state = 2 Then
  188.     'stores access parameters in the user record
  189.     retf = send_reply("200 MODE command executed.", Id_User)
  190.     users(Id_User).data_tx_mode = Argument(0)
  191.   Else
  192.     retf = send_reply("530 User not logged in.", Id_User)
  193.   End If
  194.  
  195.   Case "RETR": 'RETR <pathname>
  196.   If users(Id_User).state = 3 Then
  197.     Full_Name = ChkPath(Id_User, Argument(0))
  198.     'file exist?
  199.     i = FileLen(Full_Name)
  200.     If Err.Number = 0 Then 'Yes
  201.       'controls access rights
  202.       DummyS = UserIDs.No(users(Id_User).list_index).Priv(1).Accs
  203.       If InStr(DummyS, "R") Then
  204.         retf = open_data_connect(Id_User)
  205.         'initializes record which contains file parameters
  206.         files_info(Id_User).Full_Name = Full_Name
  207.         files_info(Id_User).data_representation = users(Id_User).data_representation
  208.         files_info(Id_User).open_file = False
  209.         files_info(Id_User).retr_stor = 0
  210.         'enables timer to send data on connection
  211.         FtpServ.Timer1(Id_User).Enabled = True
  212.       Else
  213.         'the user can't retrieves files
  214.         retf = send_reply("550 You can't take this file action.", Id_User)
  215.         retf = close_data_connect(Id_User)
  216.       End If
  217.     ElseIf (Err.Number > 51 And Err.Number < 77) Or (Err.Number > 707 And Err.Number < 732) Then
  218.       'no existing file
  219.       retf = send_reply("550 RETR command not executed: " & Error$, Id_User)
  220.       retf = close_data_connect(Id_User)
  221.     Else
  222.       FtpServ.StatusBar.Panels(1) = "Error " & Err.Number & " occurred."
  223.       retf = close_data_connect(Id_User)
  224.       retf = logoff(Id_User)
  225.       'End
  226.     End If
  227.   ElseIf users(Id_User).state = 2 Then
  228.     retf = send_reply("425 Can't open data connection.", Id_User)
  229.   Else
  230.     retf = send_reply("530 User not logged in.", Id_User)
  231.   End If
  232.  
  233.   Case "STOR": 'STOR <pathname>
  234.   If users(Id_User).state = 3 Then
  235.     Full_Name = ChkPath(Id_User, Argument(0))
  236.     'controls access rights
  237.     DummyS = UserIDs.No(users(Id_User).list_index).Priv(1).Accs
  238.     If InStr(DummyS, "W") Then
  239.       retf = open_data_connect(Id_User)
  240.       'initializes record which contains file parameters
  241.       files_info(Id_User).Full_Name = Full_Name
  242.       files_info(Id_User).data_representation = users(Id_User).data_representation
  243.       files_info(Id_User).open_file = False
  244.       files_info(Id_User).retr_stor = 1
  245.       'enables timer to receive data on connection
  246.       FtpServ.Timer1(Id_User).Enabled = True
  247.     Else
  248.       'the user can't stores files
  249.       retf = send_reply("550 You can't take this file action.", Id_User)
  250.       retf = close_data_connect(Id_User)
  251.     End If
  252.   ElseIf users(Id_User).state = 2 Then
  253.     retf = send_reply("425 Can't open data connection.", Id_User)
  254.   Else
  255.     retf = send_reply("530 User not logged in.", Id_User)
  256.   End If
  257.  
  258.   Case "RNFR":  'RNFR <pathname>
  259.   If users(Id_User).state = 2 Then
  260.     Full_Name = ChkPath(Id_User, Argument(0))
  261.     'file exists?
  262.     i = FileLen(Full_Name)
  263.     If Err.Number = 0 Then 'Yes
  264.       'controls access rights
  265.       DummyS = UserIDs.No(users(Id_User).list_index).Priv(1).Accs
  266.       If InStr(DummyS, "M") Then
  267.         'The user can updates files.
  268.         'The name of file to rename is temporarily stored in the user record.
  269.         users(Id_User).temp_data = Full_Name
  270.         'next command must be a RNTO
  271.         users(Id_User).state = 6
  272.         retf = send_reply("350 ReName command expect further information.", Id_User)
  273.       Else
  274.         'the user can't writes on files
  275.         retf = send_reply("550 You can't take this file action.", Id_User)
  276.       End If
  277.     ElseIf (Err.Number > 51 And Err.Number < 77) Or (Err.Number > 707 And Err.Number < 732) Then
  278.       'no existing file
  279.       retf = send_reply("550 RNFR command not executed: " & Error$, Id_User)
  280.     Else
  281.       FtpServ.StatusBar.Panels(1) = "Error " & Err.Number & " occurred."
  282.       retf = logoff(Id_User)
  283.       'End
  284.     End If
  285.   Else
  286.     retf = send_reply("530 User not logged in.", Id_User)
  287.   End If
  288.  
  289.   Case "RNTO":  'RNTO <pathname>
  290.   If users(Id_User).state = 6 Then
  291.     Full_Name = ChkPath(Id_User, Argument(0))
  292.     Name users(Id_User).temp_data As Full_Name
  293.     If Err.Number = 0 Then
  294.       users(Id_User).state = 2
  295.       'file exists
  296.       retf = send_reply("350 ReName command executed.", Id_User)
  297.     ElseIf (Err.Number > 51 And Err.Number < 77) Or (Err.Number > 707 And Err.Number < 732) Then
  298.       'no existing file
  299.       retf = send_reply("550 RNTO command not executed: " & Error$, Id_User)
  300.     Else
  301.       FtpServ.StatusBar.Panels(1) = "Error " & Err.Number & " occurred."
  302.       retf = logoff(Id_User)
  303.       'End
  304.     End If
  305.   Else
  306.     retf = send_reply("530 User not logged in.", Id_User)
  307.   End If
  308.   
  309.   Case "DELE":  'DELE <pathname>
  310.   If users(Id_User).state = 2 Then
  311.     Full_Name = ChkPath(Id_User, Argument(0))
  312.     'controls access rights
  313.     DummyS = UserIDs.No(users(Id_User).list_index).Priv(1).Accs
  314.     If InStr(DummyS, "K") Then
  315.       'the user can updates files
  316.       Kill Full_Name
  317.       If Err.Number = 0 Then
  318.         'file exists
  319.         retf = send_reply("250 DELE command executed.", Id_User)
  320.       ElseIf (Err.Number > 51 And Err.Number < 77) Or (Err.Number > 707 And Err.Number < 732) Then
  321.         'file no exists
  322.         retf = send_reply("550 DELE command not executed: " & Error$, Id_User)
  323.       Else
  324.         FtpServ.StatusBar.Panels(1) = "Error " & Err.Number & " occurred."
  325.         retf = logoff(Id_User)
  326.         'End
  327.       End If
  328.     Else
  329.       'the user can't delete files
  330.       retf = send_reply("550 You can't take this file action.", Id_User)
  331.     End If
  332.   Else
  333.     retf = send_reply("530 User not logged in.", Id_User)
  334.   End If
  335.   
  336.   Case "RMD", "XRMD": 'RMD <pathname>
  337.   If users(Id_User).state = 2 Then
  338.     PathName = ChkPath(Id_User, Argument(0))
  339.     'controls access rights
  340.     DummyS = UserIDs.No(users(Id_User).list_index).Priv(1).Accs
  341.     If InStr(DummyS, "D") Then
  342.       'the user can updates files
  343.       Kill PathName & "\*.*"
  344.       If Err.Number = 53 Or Err.Number = 708 Then Err.Number = 0 'empty directory
  345.       RmDir PathName
  346.       If Err.Number = 0 Then
  347.         'directory exists
  348.         retf = send_reply("250 RMD command executed.", Id_User)
  349.       ElseIf (Err.Number > 51 And Err.Number < 77) Or (Err.Number > 707 And Err.Number < 732) Then
  350.         'directory no exists
  351.         retf = send_reply("550 RMD command not executed: " & Error$, Id_User)
  352.       Else
  353.         FtpServ.StatusBar.Panels(1) = "Error " & Err.Number & " occurred."
  354.         retf = logoff(Id_User)
  355.         'End
  356.       End If
  357.     Else
  358.       'the user can't delete files
  359.       retf = send_reply("550 You can't take this file action.", Id_User)
  360.     End If
  361.   Else
  362.     retf = send_reply("530 User not logged in.", Id_User)
  363.   End If
  364.  
  365.   Case "MKD", "XMKD": 'MKD <pathname>
  366.   If users(Id_User).state = 2 Then
  367.     PathName = ChkPath(Id_User, Argument(0))
  368.     'controls access rights
  369.     DummyS = UserIDs.No(users(Id_User).list_index).Priv(1).Accs
  370.     If InStr(DummyS, "M") Then
  371.       'the user can updates files
  372.       MkDir PathName
  373.       If Err.Number = 0 Then
  374.         'the directory is been created
  375.         retf = send_reply("257 " & Argument(0) & " created.", Id_User)
  376.       ElseIf (Err.Number > 51 And Err.Number < 77) Or (Err.Number > 707 And Err.Number < 732) Then
  377.         'the directory isn't been created
  378.         retf = send_reply("550 MKD command not executed: " & Error$, Id_User)
  379.       Else
  380.         FtpServ.StatusBar.Panels(1) = "Error " & Err.Number & " occurred."
  381.         retf = logoff(Id_User)
  382.         'End
  383.       End If
  384.     Else
  385.       'the user can't write on files
  386.       retf = send_reply("550 You can't take this file action.", Id_User)
  387.     End If
  388.   Else
  389.     retf = send_reply("530 User not logged in.", Id_User)
  390.   End If
  391.  
  392.   Case "PWD", "XPWD": 'PWD
  393.   If users(Id_User).state = 2 Then
  394.     PathName = users(Id_User).cur_dir
  395.     PathName = Right$(PathName, Len(PathName) - 2)
  396.     retf = send_reply("257 """ & PathName & """ is the current directory.", Id_User)
  397.   Else
  398.     retf = send_reply("530 User not logged in.", Id_User)
  399.   End If
  400.  
  401.   Case "LIST", "NLST"   'LIST <pathname>Or InStr(Argument(0), "-L")
  402.     LIST_NLST Id_User, Kwrd, Argument(0)
  403.   
  404.   Case "SYST":  'SYST
  405.   DummyS = "215 IBM PC TCP/IP"
  406.   retf = send_reply(DummyS, Id_User)
  407.  
  408.   Case "STAT":  'STAT <pathname>
  409.     retf = send_reply("200 Not Implemented..", Id_User)
  410.  
  411.   Case "HELP":  'HELP <string>
  412.   DummyS = "214-This is the list of recognized FTP commands:"
  413.   retf = send_reply(DummyS, Id_User)
  414.     DummyS = "214-   USER  PASS  CWD   XCWD  CDUP  XCUP  QUIT  PORT" & vbCrLf _
  415.            & "214-   PASV  TYPE  STRU  MODE  RETR  STOR  RNFR  RNTO" & vbCrLf _
  416.            & "214-   DELE  RMD   XRMD  MKD   XMKD  PWD   XPWD" & vbCrLf _
  417.            & "214    LIST  NLST  SYST  STAT  HELP  NOOP"
  418.   retf = send_reply(DummyS, Id_User)
  419.  
  420.   Case "NOOP": 'NOOP
  421.   retf = send_reply("200 NOOP command executed.", Id_User)
  422.  
  423. End Select
  424.  
  425. End Function
  426.  
  427. Private Function ChkPath(ByVal Id_User As Integer, ByVal Arg As String) As String
  428.     If Left$(Arg, 1) = "\" Then
  429.       ChkPath = DEFAULT_DRIVE & Arg                   'absolute path
  430.     Else
  431.       If Right$(users(Id_User).cur_dir, 1) = "\" Then 'relative path
  432.         ChkPath = users(Id_User).cur_dir & Arg        'radix
  433.       Else
  434.         ChkPath = users(Id_User).cur_dir & "\" & Arg
  435.       End If
  436.     End If
  437. End Function
  438.  
  439. Private Sub SendBuffer(Id_User As Integer, ByRef Buffer As String)
  440. Dim ii As Long
  441.   Debug.Print Buffer
  442.   'sends data in buffer on data connection;
  443.   'data are sending in blocks of 1024 bytes
  444.   ii = 1
  445.   Do While Mid$(Buffer, ii, 1024) <> ""
  446.     retf = send_data(Mid$(Buffer, ii, 1024), Id_User)
  447.     If retf < 0 Then
  448.       retf = WSAGetLastError()
  449.       If retf = WSAEWOULDBLOCK Then
  450.         'try again
  451.       Else
  452.         'error on send
  453.         Exit Do
  454.       End If
  455.     Else
  456.       ii = ii + 1024
  457.     End If
  458.     DoEvents
  459.   Loop
  460.   Buffer = ""
  461. End Sub
  462.  
  463.  
  464. Private Sub LIST_NLST(ByVal Id_User As Integer, ByVal Typ As String, ByVal Arg As String)
  465. Dim File_Name As String, name_ As String, exte_ As String
  466. Dim DummyS As String
  467. Dim SepN As Integer
  468. Dim Full_Name As String 'pathname & file name
  469. Dim PathName As String, Buffer As String
  470.  
  471.   If users(Id_User).state = 3 Then
  472.     If InStr(Arg, "-a -L") Then Arg = Left(Arg, (InStr(Arg, "-a -L") - 1))
  473.     If Arg = "" Then
  474.       'if LIST/NLST command has no argument the working directory is the current directory
  475.       PathName = users(Id_User).cur_dir
  476.     Else
  477.       PathName = ChkPath(Id_User, Arg)
  478.     End If
  479.     If (GetAttr(PathName) And 16) <> 0 Then
  480.       '--- the pathname indicates a directory
  481.       'if radix then elides final backslash
  482.       If Right$(PathName, 1) = "\" Then
  483.         PathName = Left$(PathName, Len(PathName) - 1)
  484.       End If
  485.       File_Name = Dir$(PathName & "\*.*", 16)
  486.       'rebuilds the full file name
  487.       '(pathname & file name)
  488.       Full_Name = PathName & "\" & File_Name
  489.     Else
  490.       'the pathname indicates a file
  491.       Full_Name = PathName
  492.       File_Name = Dir$(Full_Name)
  493.     End If
  494.     If Err.Number = 0 Then
  495.       'opens data connection
  496.       retf = open_data_connect(Id_User)
  497.       Do
  498.         If File_Name = "." Or File_Name = ".." Then
  499.           'parent directories
  500.           DummyS = Format$(File_Name, "@@@@@@@@@@@@!") & " <DIR>"
  501.         ElseIf GetAttr(Full_Name) = 16 Then
  502.           'subdirectory
  503.           SepN = InStr(File_Name, ".")
  504.           If SepN <> 0 Then
  505.             'name
  506.             name_ = Left$(File_Name, SepN - 1)
  507.             'extension
  508.             exte_ = Mid$(File_Name, SepN + 1)
  509.           Else
  510.             name_ = File_Name
  511.             exte_ = "   "
  512.           End If
  513.           DummyS = "drwxr-xr-x   1 user    group  "
  514.           If Typ = "LIST" Then
  515.             DummyS = DummyS & Format$(FileLen(Full_Name), " @@@@@@@@@") _
  516.              & " " & Format$(FileDateTime(Full_Name), " mmm dd hh:nn ") & File_Name
  517.           End If
  518.         Else
  519.           'file
  520.           SepN = InStr(File_Name, ".")
  521.           If SepN <> 0 Then
  522.             'name
  523.             name_ = Left$(File_Name, SepN - 1)
  524.             'extension
  525.             exte_ = Mid$(File_Name, SepN + 1)
  526.           Else
  527.             name_ = File_Name
  528.             exte_ = "   "
  529.           End If
  530.           DummyS = "-rwxr--r--   1 user    group  "
  531.           If Typ = "LIST" Then
  532.             DummyS = DummyS & Format$(FileLen(Full_Name), " @@@@@@@@@") _
  533.              & " " & Format$(FileDateTime(Full_Name), " mmm dd hh:nn ") & File_Name
  534.           End If
  535.         End If
  536.         Buffer = Buffer & DummyS & vbCrLf
  537.         File_Name = Dir$
  538.         If File_Name = "" Then Exit Do
  539.         Full_Name = PathName & "\" & File_Name
  540.       Loop While True
  541.       SendBuffer Id_User, Buffer
  542.       'close data connection
  543.       retf = send_reply("226 " & Typ & " command completed.", Id_User)
  544.       retf = close_data_connect(Id_User)
  545.     ElseIf (Err.Number > 51 And Err.Number < 77) Or (Err.Number > 707 And Err.Number < 732) Then
  546.       retf = send_reply("450 " & Typ & " command not executed: " & Error$, Id_User)
  547.       retf = close_data_connect(Id_User)
  548.     Else
  549.       FtpServ.StatusBar.Panels(1) = "Error " & Err.Number & " occurred."
  550.       retf = close_data_connect(Id_User)
  551.       retf = logoff(Id_User)
  552.       'End
  553.     End If
  554.   ElseIf users(Id_User).state = 2 Then
  555.     retf = send_reply("425 Can't open data connection.", Id_User)
  556.   Else
  557.     retf = send_reply("530 User not logged in.", Id_User)
  558.   End If
  559. End Sub
  560.